package com.peak.distribution.service.order;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.peak.distribution.entity.admin.DisConfig;
import com.peak.distribution.entity.agent.DisAgent;
import com.peak.distribution.entity.agent.DisAgentSales;
import com.peak.distribution.entity.goods.DisGoods;
import com.peak.distribution.entity.goods.DisGoodsPriceRule;
import com.peak.distribution.entity.order.DisOrder;
import com.peak.distribution.entity.order.DisOrderGoods;
import com.peak.distribution.entity.order.DisOrderLogistics;
import com.peak.distribution.entity.order.DisOrderReceiver;
import com.peak.distribution.enums.Constants;
import com.peak.distribution.enums.OrderStatus;
import com.peak.distribution.enums.OrderType;
import com.peak.distribution.enums.PayChannel;
import com.peak.distribution.enums.SmsType;
import com.peak.distribution.exception.DistributionError;
import com.peak.distribution.exception.DistributionException;
import com.peak.distribution.jms.JmsProducerHandler;
import com.peak.distribution.manager.admin.DisConfigManager;
import com.peak.distribution.manager.agent.DisAgentSalesManager;
import com.peak.distribution.manager.goods.DisGoodsManager;
import com.peak.distribution.manager.order.DisOrderLogisticsManager;
import com.peak.distribution.manager.order.DisOrderManager;
import com.peak.distribution.manager.order.DisOrderReceiverManager;
import com.peak.distribution.service.agent.DisAgentService;
import com.peak.distribution.tools.Kuaidi100Tools;
import com.peak.distribution.tools.Kuaidi100Tools.KuaidiPost;
import com.peak.distribution.tools.Kuaidi100Tools.KuaidiState;
import com.peak.spring.boot.api.repository.FilterParam;
import com.peak.spring.boot.builder.repository.FilterParamBuilder;
import com.peak.spring.boot.core.mapper.JsonMapper;
import com.peak.spring.boot.tools.Converts;
import com.peak.spring.boot.tools.Dates;
import com.peak.spring.boot.tools.Emptys;
import com.peak.spring.boot.tools.Identities;

import lombok.extern.slf4j.Slf4j;

@Service
@Transactional
@Slf4j
public class DisOrderServiceImpl implements DisOrderService {
	
	@Value("${free.shipping.min.order.price}")
	private Integer freeShippingMinOrderPrice;
	
	@Value("${default.shipping.price}")
	private Integer defaultShippingPrice;
	
	@Value("${order.alert.shipper.mobile.no}")
	private String shipperMobile;
	
	@Autowired
	private DisOrderManager orderManager;
	
	@Autowired
	private DisGoodsManager goodsManager;
	
	@Autowired
	private DisAgentService agentService;
	
	@Autowired
	private DisOrderReceiverManager orderReceiverManager;
	
	@Autowired
	private JmsProducerHandler jmsProducerHandler;

	@Autowired
	private DisAgentSalesManager agentSalesManager;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
	
	@Autowired
	private DisOrderLogisticsManager orderLogisticsManager;
	
	@Autowired
	private DisConfigManager configManager;

	@Override
	public DisOrder add(String cartJson, Integer receiverId, String payChannel, String remark) {
		JsonMapper mapper = JsonMapper.nonDefaultMapper();
		List<DisGoods> goodses = Lists.newArrayList();
		// 转换json对象为List
		List<Map<String, Object>> carts = mapper.fromJson(cartJson, mapper.contructCollectionType(ArrayList.class, HashMap.class));
		DisOrder order = new DisOrder();
		// 生成orderNO
		order.setOrderNo(Identities.twitterSnowflake(Constants.TWITTER_SNOWFLAKE_ORDER_NO, Constants.TWITTER_SNOWFLAKE_DATACENTERID));
		// 设置订单为消费订单
		order.setOrderType(OrderType.CONSUME_ORDER);
		// 当前时间
		order.setOrderTime(Dates.now());
		// 备注
		order.setRemark(remark);
		// 支付类型
		try {
			order.setPayChannel(PayChannel.valueOf(payChannel));
		} catch (Exception e) {
			throw new DistributionException(DistributionError.PAY_CHANNEL_NOT_SUPPORT);
		}
		
		int goodsFee = 0;
		double goodsWeight = 0;
		// 把购物车的商品生成订单商品的快照
		for (Map<String, Object> map : carts) {
			Integer goodsId = Converts.toInteger(map.get("goodsId"));
			Integer quantity = Converts.toInteger(map.get("quantity"));
			DisGoods goods = goodsManager.getOne(goodsId);
			if (!goods.getStatus()) {
				throw new DistributionException(DistributionError.GOODS_INV_NOT_ENOUGH.getMessage(goods.getName()));
			}
			if (quantity.intValue() > goods.getInvCount().intValue()) {
				throw new DistributionException(DistributionError.GOODS_INV_NOT_ENOUGH.getMessage(goods.getName()));
			}
			
			// 计算商品实际价格
			DisGoodsPriceRule rule = goods.getRules().stream().filter(p -> (quantity >= p.getMinQuantity() && quantity <= p.getMaxQuantity())).findFirst().get();
			// 创建订单商品
			DisOrderGoods oGoods = new DisOrderGoods();
			oGoods.setGoods(goods);
			oGoods.setQuantity(quantity);
			oGoods.setName(goods.getName());
			oGoods.setSkuNo(goods.getSkuNo());
			oGoods.setPartNo(goods.getPartNo());
			oGoods.setUnitPrice(rule.getPrice());
			oGoods.setTotalPrice(oGoods.getQuantity() * oGoods.getUnitPrice());
			// 商品总价累加
			goodsFee += oGoods.getTotalPrice();
			// 计算商品总重量
			goodsWeight += (goods.getWeight() * quantity) / 1000;
			// 关联
			oGoods.setOrder(order);
			order.getGoodses().add(oGoods);
			// 减库存
			goods.addInvGoods(-quantity);
			goodses.add(goods);
		}
		order.setGoodsFee(goodsFee);
		order.setGoodsWeight(goodsWeight);
		// 物流费用需要计算，默认8元
		order.setShoppingFee(calculateShippingFee(order.getGoodsFee()));
		order.setOrderFee(order.getGoodsFee() + order.getShoppingFee());
		// 加入当前登录的代理商
		DisAgent agent = agentService.getCurrentAgent();
		order.setAgent(agent);
		
		//设置收货人地址
		DisOrderReceiver receiver = orderReceiverManager.getOne(receiverId);
		order.setReceiver(receiver);
		// 保存订单
		orderManager.save(order);
		// 商品库存减少
		goodsManager.save(goodses);
		
		// 订单状态变更消息
		jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.UNPAID);
		return order;
	}

	@Override
	public int calculateShippingFee(Integer goodsFee) {
		if (goodsFee >= freeShippingMinOrderPrice * 100) {
			return 0;
		} else {
			return defaultShippingPrice * 100;
		}
	}

	@Override
	public void cancel(DisAgent agent, Integer orderId) {
		DisOrder order = orderManager.getOne(orderId);
		if (Emptys.isEmpty(order)) {
			throw new DistributionException(DistributionError.ORDER_NOT_FOUND);
		}
		// 对象比较的时候遇到了代理对象的问题，还是直接比id比较好
		if (!order.getAgent().getId().equals(agent.getId())) {
			throw new DistributionException(DistributionError.ORDER_CANCEL_NOT_SELF_ORDER);
		}
		// 判断状态
		switch (order.getStatus()) {
		case UNPAID:
		case DELIVERING:
			break;
		default:
			throw new DistributionException(DistributionError.ORDER_CANCEL_STATUS_ERROR);
		}
		// 把商品的库存还回去
		List<DisGoods> goodses = Lists.newArrayList();
		int sumGoods = 0;
		for (DisOrderGoods oGoods : order.getGoodses()) {
			DisGoods goods = oGoods.getGoods();
			goods.addInvGoods(oGoods.getQuantity());
			goodses.add(goods);
			// 统计总商品数量
			sumGoods += oGoods.getQuantity();
		}
		goodsManager.save(goodses);
		// 把代理商的销量减下去
		int goodsFee = order.getGoodsFee();
		DisAgentSales sales = agentSalesManager.getByAgentId(order.getAgent().getId());
		if (Emptys.isNotEmpty(sales)) {
			sales.addSales(-goodsFee);
			sales.addTotalSales(-goodsFee);
			sales.addSalesGoods(-sumGoods);
			sales.setSign(passwordEncoder.encode(sales.getSignSource()));
		}
		agentSalesManager.save(sales);
		// 把代理商团队的销量减下去
		List<DisAgentSales> teamSaleses = agentSalesManager.getTeamSalesByAgentId(order.getAgent().getId());
		if (Emptys.isNotEmpty(teamSaleses)) {
			for (DisAgentSales teamSales : teamSaleses) {
				teamSales.addSales(-goodsFee);
				teamSales.addTotalSales(-goodsFee);
				teamSales.addSalesGoods(-sumGoods);
				teamSales.setSign(passwordEncoder.encode(teamSales.getSignSource()));
			}
		}
		agentSalesManager.save(teamSaleses);
		// 改到取消的状态
		jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.CANCELLED);
	}

	@Override
	public void confirmPaid(Integer orderId) {
		DisOrder order = orderManager.getOne(orderId);
		if (Emptys.isEmpty(order)) {
			throw new DistributionException(DistributionError.ORDER_NOT_FOUND);
		}
		if (!OrderStatus.UNPAID.equals(order.getStatus())) {
			throw new DistributionException(DistributionError.ORDER_CONFIRM_STATUS_ERROR);
		}
		
		Integer agentId = order.getAgent().getId();
		DisAgentSales sales = agentSalesManager.getByAgentId(agentId);
		
		if (!passwordEncoder.matches(sales.getSignSource(), sales.getSign())) {
			throw new DistributionException(DistributionError.SALES_SIGN_ERROR);
		}
		
		List<DisAgentSales> teamSaleses = agentSalesManager.getTeamSalesByAgentId(agentId);
		for (DisAgentSales tSales : teamSaleses) {
			if (!passwordEncoder.matches(tSales.getSignSource(), tSales.getSign())) {
				throw new DistributionException(DistributionError.SALES_TEAM_SIGN_ERROR);
			}
		}
		// 账户的变动暂时没有，那个是支付的时候用到
		
		// 累计销量
		jmsProducerHandler.addUpSales(order);
		
		// 改到代发货的状态
		jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.DELIVERING);
	}

	@Override
	public void shipping(Integer orderId, String express, String waybillNo) {
		DisOrder order = orderManager.getOne(orderId);
		if (Emptys.isEmpty(order)) {
			throw new DistributionException(DistributionError.ORDER_NOT_FOUND);
		}
		if (!OrderStatus.DELIVERING.equals(order.getStatus())) {
			throw new DistributionException(DistributionError.ORDER_DELIVERING_STATUS_ERROR);
		}
		// 记录快递公司和运单号
		DisOrderLogistics ol = new DisOrderLogistics();
		ol.setDeliverTime(Dates.now());
		ol.setExpress(express);
		ol.setWaybillNo(waybillNo);
		orderLogisticsManager.save(ol);
		// 物流信息关联到订单上
		order.setLogistics(ol);
		orderManager.save(order);
		
		// 改到代发货的状态
		jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.SHIPPED);
		jmsProducerHandler.addAward(order);
	}

	@Override
	public void closeUnpayOrder() {
		// 找24小时之前的订单，切状态还是未支付
		Date last24Hour = Dates.addHour(Dates.now(), -24);
		List<FilterParam> filters = FilterParamBuilder.create().eq("status", OrderStatus.UNPAID).lte("orderTime", last24Hour).build();
		List<DisOrder> orders = orderManager.findList(filters);
		log.info("待清理订单记录{}条", Emptys.isEmpty(orders) ? 0 : orders.size());
		if (Emptys.isNotEmpty(orders)) {
			orders.stream().forEach(order -> jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.CLOSE));
		}
	}

	@Override
	public void alertDeliveryOrder() {
		List<FilterParam> filters = FilterParamBuilder.create().eq("status", OrderStatus.DELIVERING).build();
		int count = orderManager.count(filters);
		log.info("待发货订单记录{}条", count);
		if (count > 0) {
			DisConfig config = configManager.getByKeyword(shipperMobile);
			if (config != null) {
				jmsProducerHandler.sendSmsJms(SmsType.SHIPPING_ALERT, config.getContent(), Converts.toString(count));
			} else {
				throw new DistributionException(DistributionError.CONFIG_NOT_FOUND.getMessage(shipperMobile));
			}
		}
	}

	@Override
	public void checkReceiveOrder() {
		List<FilterParam> filters = FilterParamBuilder.create().eq("status", OrderStatus.SHIPPED).build();
		List<DisOrder> orders = orderManager.findList(filters);
		log.info("代收货订单记录{}条", (Emptys.isEmpty(orders) ? 0 : orders.size()));
		if (Emptys.isNotEmpty(orders)) {
			for (DisOrder order : orders) {
				DisOrderLogistics logistics = order.getLogistics();
				String orderNo = order.getOrderNo();
				if (Emptys.isEmpty(logistics)) {
					log.error("{}订单的物流信息错误", orderNo);
					continue;
				}
				String waybillNo = logistics.getWaybillNo();
				if (Emptys.isEmpty(waybillNo)) {
					log.error("{}订单的物流单号为空", orderNo);
					continue;
				}
				KuaidiPost post = Kuaidi100Tools.query(waybillNo);
				if ("200".equals(post.getStatus())) {
					if (KuaidiState.QIAN_SHOU.ordinal() == Converts.toInt(post.getState())) {
						jmsProducerHandler.orderChangeStatus(order.getId(), OrderStatus.SUCCEED);
					}
				} else {
					log.error("{}订单的物流单号{}错误", orderNo, waybillNo);
				}
				try {
					// 扒别人的数据，还是不要太频繁的好
					Thread.sleep(20 * 1000);
				} catch (InterruptedException e) {
					log.error("线程等待失败", e);
				}
			}
		}
	}

}
